Canvas is the object that you send messages to in order to draw. You can only send these messages in response to the draw or pointer-req messages sent to a drawable view.
The canvas represents the drawable surface of your drawable view. It imposes a coordinate system upon the display. Initially, the point 0,0 is the upper left hand corner and, the coordinates increase down and to the right. The scaling is one unit to one pixel on the screen. You can change the coordinate system to something more convenient, see set-unit-size below.
[ This drawing system is not totally well-defined at the moment. For example, under Macintosh, lines draw down and to the right, whereas on Windows they are centered. Furthermore, there are some items that will most likely change in the future. See the other bracketed comments. ]
Point Arguments
Many messages to canvas take one or more points as arguments. You can specify these points in a number of ways, which ever is most convenient to your program. Here we use the example of draw-rectangle which takes two points (the upper left and lower right corners). Each of these is equivalent:
canvas draw-rectangle 10, 20, 80, 90.
four coordinates
p1 := new point of 10, 20.
p2 := new point of 80, 90.
canvas draw-rectangle p1, p2.
two points
a := new array size 4.
a @ 1 := 10.
a @ 2 := 20.
a @ 3 := 80.
a @ 4 := 90.
canvas draw-rectangle a.
an array (or group) of coordinates
g := new group.
g add (new point of 10, 20).
g add (new point of 80, 90).
canvas draw-rectangle g.
a group (or array) or points
In the descriptions below, generally the coordinate form will be shown, although any form will work. If the message takes other arguments, then the points always come last.
Basic Drawing
Most of these operations come in ‘draw-’ and ‘fill-’ variants. When drawing, the edge of the figure is stroked with a line using the current settings of line-thickness and paint. When filling, the figure is solidly filled in with the paint. Filling does not also draw the line on the edge.
canvas draw-line x1, y1, x2, y2
draws a line between the two points
Draws a line between the two points. Drawing a line from point a to point b is the same as drawing it in the other order.
canvas draw-rectangle x1, y1, x2, y2
draws a rectangle bounded by the two points
canvas fill-rectangle x1, y1, x2, y2
fills a rectangle bounded by the two points
canvas draw-ellipse x1, y1, x2, y2
draws an ellipse bounded by the two points
canvas fill-ellipse x1, y1, x2, y2
fills an ellipse bounded by the two points
These messages draw or fill the indicated graphic figure. Ellipses are defined to fit within the given rectangle.
canvas draw-window draws the display edge
canvas fill-window fills the display
These messages draw or fill entire view, including any borders that set-unit-size may have created.
[ Window is a poor choice of name for these messages. ]
» Fill-window is an easy way to clear the view to a color other than white.
canvas draw-polygon g draws a polygon
canvas fill-polygon g fills a polygon
These messages draw or fill a polygon. The polygon is usually specified with a group or array of points or coordinates. If there are four or fewer points, the points may be specified directly as arguments. The polygon is always closed, even if the last point doesn’t equal the first.
canvas draw-bezier p1, p2, p3, p4 segments n
draws a bezier curve from p1 to p4
A bezier curve is specified with two endpoints, p1 & p4, and two control points, p2 & p3. You can think of the curve starting out from p1, heading for p2, then curves to end up at p4 as if it was coming from p3. The curve is approximated by line segments. If you specify n, that number of segments is used: less is faster, more is more accurate. If you leave n out, a suitable value will be chosen.
Drawing State
These two properties of canvas are used by the basic and text drawing messages.
canvas.paint the current paint value
canvas.paint := v set the current paint value
Paint is the gray-scale value to draw with. It is a number between 0 (black) and 100 (white). [ These numbers are probably backwards from what they should be. ]
canvas.line-thickness the current line width
canvas.line-thickness := v set the current line width
This is the width of lines. The value is interpreted according to the current coordinate grid.
Text Drawing
canvas draw-text t, x, y draw the string t
Draws the string t at the indicated point. The point is the left end of the baseline that the text sits on. The text is drawn in the current text size, font, style, as set by the set-font message and in the current color.
canvas set-font size s
set just the font size
canvas set-font size s group i italic bold
set all of the font characteristics
The size s is interpreted in the current units, initially (if you haven’t called set-unit-size) it is in pixels. Group, if specified, sets the font as follows:
canvas set-font group 1 ԨŠa Serif font
canvas set-font group 2 ԨŠa Sans-Serif font
canvas set-font group 3 ԨŠa Headline font
You can specify bold and/or italic versions of the font. You can specify just the size, if you want the other font settings to remain the same.
canvas measure-text t the width of the string if drawn
Returns the width of the string t if it were drawn. The text is measured using the current text size, font, style, as set by the set-font message. The width is returned in the current units. Note that when measuring italic text, the top part of the text might lean further right than the result of the message indicates.
Units
canvas set-unit-size
reset the units to pixels
canvas set-unit-size x, y
scale the display to x, y units
canvas set-unit-size x, y integer-scale
scale the display, keeping integer ratios
These messages change the coordinate system used for drawing. The first message form (no arguments) resets the coordinate system so that the point 0,0 is at the upper left of the view, and each unit is equal to one pixel, increasing down and to the right.
The second and third message forms will create a coordinate system that has x units horizontally and y units vertically. The units will be scaled so that this x by y grid takes up as much of the view as possible. Note that unless the aspect ration of x to y is the same as the view’s, there will be border space around the grid. For example, if the view is 100 x 150 pixels:
canvas set-unit-size 10, 10
fi  
canvas set-unit-size 5, 2
fi  
The scaling affects all future values passed in messages to canvas. In particular, the line-thickness and size argument to set-font are interpreted in these new units. However, the current settings are not affected. For example, assuming the view is 150 by 100 pixels as above:
The integer-scale flag causes the ratio between pixels and units to be an integer or the inverse of an integer. This has the advantage that drawing maps to the screen pixels cleanly without round-off artifacts. However, to achieve the integer ratio and still fit the coordinate grid on the screen, the grid may be considerably reduced.
canvas pixels-per-unit return scale factor
This message returns the number of pixels per unit of the coordinate grid. If the coordinate grid is the default pixel grid, this is 1. If you have changed the coordinate system with set-unit-size, then this is the scaling factor canvas is using to draw with. In the two examples above, the results of this message would be:
canvas pixels-per-unit ԨŠ10
canvas pixels-per-unit ԨŠ30
canvas get-bounds return the view bounds
The get-bounds message returns to you a rectangle that this the full boundary of the view. If the coordinate grid is the default pixel grid, then this is the size of the view in pixels. If you have changed the coordinate system with set-unit-size, then this is the bounding rectangle in those units, which may be bigger than what you asked for. In the two examples above, the results of this message would be:
canvas get-bounds ԨŠ(-2.5, 0) :: (12.5, 10)
canvas get-bounds ԨŠ(0, -0.667) :: (5, 2.667)
Pointer
canvas.pointer the location of the pointer
canvas.pointer-active true if the pointer is pressed
These messages return information about the pointing device (a mouse, trackball, or pen). The location returned is relative to the current units.